package com.kehanpay.sdk.util;

import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import sun.security.util.DerInputStream;
import sun.security.util.DerValue;

public class KehanSignUtil {
	
	/**
     * URLEncoder charset
     */
    public static final String CHARSET = "UTF-8";

	/**
     * 生成请求签名
     *
     * @param data
     */
    public static String generateSign(String data,String trimmedPrivateKey )
            throws IOException {

    	trimmedPrivateKey = trimmedPrivateKey
                .replaceAll("(-+BEGIN (RSA )?PRIVATE KEY-+\\r?\\n|-+END (RSA )?PRIVATE KEY-+\\r?\\n?)", "");
        byte[] privateKeyBytes = Base64.decodeBase64(trimmedPrivateKey);

        DerInputStream derReader = new DerInputStream(privateKeyBytes);
        DerValue[] seq = derReader.getSequence(0);

        if (seq.length < 9) {
            System.out.println("Could not parse a PKCS1 private key.");
            return null;
        }

        // skip version seq[0];
        BigInteger modulus = seq[1].getBigInteger();
        BigInteger publicExp = seq[2].getBigInteger();
        BigInteger privateExp = seq[3].getBigInteger();
        BigInteger prime1 = seq[4].getBigInteger();
        BigInteger prime2 = seq[5].getBigInteger();
        BigInteger exp1 = seq[6].getBigInteger();
        BigInteger exp2 = seq[7].getBigInteger();
        BigInteger crtCoef = seq[8].getBigInteger();
        RSAPrivateCrtKeySpec spec = new RSAPrivateCrtKeySpec(modulus, publicExp, privateExp, prime1, prime2, exp1, exp2, crtCoef);

        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(spec);

            Signature signature = Signature.getInstance("SHA256withRSA");
            signature.initSign(privateKey);
            signature.update(data.getBytes(CHARSET));
            byte[] signBytes = signature.sign();

            return Base64.encodeBase64String(signBytes).replaceAll("\n|\r", "");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (SignatureException e) {
            e.printStackTrace();
        }

        return null;
    }
    
    /**
     * @param params
     * @return
     */
    public static String createJSONString(Map<String, Object> params) {
        /*Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create();
        return gson.toJson(params);*/
    	String paramsStr = JSON.toJSONString(params);
    	JSONObject paramsJson = JSONObject.parseObject(paramsStr);
		
    	List<String> keys = new ArrayList<String>(paramsJson.keySet());
		Collections.sort(keys);

		StringBuffer prestr = new StringBuffer("{");
		for (int i = 0; i < keys.size(); i++) {
			String key = keys.get(i);
			Object value = paramsJson.get(key);

			if (i == keys.size() - 1) {// 拼接时，不包括最后一个&字符
				prestr.append("\"").append(key).append("\":")
				.append((value.toString().indexOf("{")>-1?value:"\""+value+"\""));
				
			} else {
				prestr.append("\"").append(key).append("\":")
				.append((value.toString().indexOf("{")>-1?value:"\""+value+"\""))
				.append(",");
			}
		}
		prestr.append("}");
		
		return prestr.toString();
    }
    
    /** 
     * 使用 Map按key进行排序 
     * @param map 
     * @return 
     */  
    public static Map<String, Object> sortMapByKey(Map<String, Object> oriMap) {
    	
    	Map<String, Object> result = new HashMap<String, Object>(oriMap.size());
        if (oriMap == null || oriMap.size() <= 0) {
            return result;
        }
        for (String key : oriMap.keySet()) {
            Object value = oriMap.get(key);
            if (value == null || value.equals("") || key.equalsIgnoreCase("sign")) {
                continue;
            }
            result.put(key, value);
        }
        return result;
    }
    
    /** 
     * 使用 Map按key ascii码排序 
     * @param map 
     * @return 
     */  
    public static String getMapParamSortStr(Map<String, Object> map) {
		ArrayList<String> list = new ArrayList<String>();
		for (Map.Entry<String, Object> entry : map.entrySet()) {
			if (entry.getValue() != null && StringUtils.isNotBlank(String.valueOf(entry.getValue()))) {
				list.add(entry.getKey() + "=" + entry.getValue() + "&");
			}
		}
		int size = list.size();
		String[] arrayToSort = list.toArray(new String[size]);
		Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < size; i++) {
			sb.append(arrayToSort[i]);
		}
		return sb.toString();
	}

    
    /**
     * 过滤参数
     * @author  
     * @param sArray
     * @return
     */
    public static Map<String, String> paraFilter(Map<String, String> sArray) {
        Map<String, String> result = new HashMap<String, String>(sArray.size());
        if (sArray == null || sArray.size() <= 0) {
            return result;
        }
        for (String key : sArray.keySet()) {
            String value = sArray.get(key);
            if (value == null || value.equals("") || key.equalsIgnoreCase("sign")) {
                continue;
            }
            result.put(key, value);
        }
        return result;
    }
    
}
